package cn.dengta.webapp.trade.dto;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import cn.dengta.common.context.RequestContext;
import cn.dengta.webapp.base.entity.BaseEntity;
import cn.dengta.webapp.trade.entity.UserCoin;
import cn.dengta.webapp.trade.model.TradeType;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

@Getter
@Setter
@Accessors(chain = true)
public class CoinTradeDTO extends TradeDTO<Integer> implements Serializable {

	/** 【最大努力交易】；不管余额是否足够，直接进行交易，异常情况下交易后的余额可能为负数。 */
	public static final int MODE_ANY = 0;
	/** 【余额不足时快速返回】：余额不足时，不继续执行交易，直接快速返回对应的状态码 */
	public static final int MODE_FAST_RETURN = 1;
	/** 【余额不足时快速失败】：余额不足时，直接抛出异常 */
	public static final int MODE_FAST_FAIL = 2;

	/** 赠送的免费额度（没有赠送，可以为 null；如果需要扣减，请传入负数 ） */
	@Nullable
	protected Integer addFreePart;
	/**
	 * 如果本次交易有对资金进行【临时的】预冻结（基于Redis存储），则需要在交易时传入该参数，内部会自动解冻对应的资金
	 *
	 * @see cn.dengta.webapp.trade.service.UserCoinService#freezeTemporary(FreezeCoinDTO)
	 */
	@Nullable
	protected String freezeBizId;
	/**
	 * 指定本次交易的交易模式，主要指示如何处理余额不足的场景
	 * <ul>
	 *     <li>0 = 【最大努力交易】；不管余额是否足够，直接进行交易，异常情况下交易后的余额可能为负数。</li>
	 *     <li>1 = 【余额不足时跳过交易】：余额不足时，直接返回对应的状态码</li>
	 *     <li>2 = 【余额不足时快速失败】：余额不足时，直接抛出异常</li>
	 * </ul>
	 * 可使用 {@code Messager.isOK(Messager)} 判断交易是否成功；
	 * 如果不想内部直接抛出异常，也可以在返回时，通过 {@code UserCoinService.assertTradeOK(Messager) } 方法去断言抛出异常
	 *
	 * @see cn.dengta.common.model.Messager#isOK(cn.dengta.common.model.Messager)
	 * @see cn.dengta.webapp.trade.service.UserCoinService#assertTradeOK(cn.dengta.common.model.Messager)
	 */
	protected int mode = MODE_FAST_FAIL;
	/** 平台因故（活动、付费方是VIP等）额外支出的【赠送】钻石数（直接以赠送钻石的性质结算给对应的收益用户） */
	protected int platformBonus;
	/** 平台免费，增送活动积分 */
	protected int platformFreeBonus;
	/** 充值金额（用于统计累计充值金额 ） */
	@Nullable
	protected BigDecimal rechargeAmount;
	/** 等价物数量：一般用于存储 音视频通话 的通话时长 或者 充值的人民币（单位：分） */
	protected Integer equivalentAmount;
	/** 收益模式：-1=暂不处理收益；0=默认；1=直接增加收益 */
	protected int incomeMode;
	/** 是否后置处理 */
	protected boolean handleToConfirm;
	/** 直播间id */
	protected Long liveId;
	/** Ai标识 */
	protected Long aiId;
	/** 收益用户所对应的比例 如：30=30% */
	protected Integer incomeRatio;
	/**
	 * 如果外部已经进行对钻石账户进行了 FOR UPDATE，则可以直接传入，内部将直接使用此对象。
	 * 要求必须是 fromUserId 的账户。
	 */
	protected transient UserCoin userCoinForUpdate;

	public static CoinTradeDTO of(Long userId, TradeType tradeType, @Nullable Long toUserId, Integer tradeAmount, @Nonnull BaseEntity assocObj, String ip, Date now) {
		CoinTradeDTO dto = new CoinTradeDTO();
		dto.init(userId, tradeType, toUserId, tradeAmount, assocObj);
		dto.init(ip, now);
		return dto;
	}

	public static CoinTradeDTO of(Long userId, TradeType tradeType, Long toUserId, Integer tradeAmount, @Nonnull BaseEntity assocObj, RequestContext req) {
		return of(userId, tradeType, toUserId, tradeAmount, assocObj, req.clientIP(), req.now());
	}

	public static CoinTradeDTO of(Long userId, TradeType tradeType, Integer tradeAmount, @Nonnull BaseEntity assocObj, RequestContext req) {
		return of(userId, tradeType, null, tradeAmount, assocObj, req.clientIP(), req.now());
	}

	@Override
	public CoinTradeDTO setRemark(@Nullable String remark) {
		super.setRemark(remark);
		return this;
	}

}
